プロキシサーバーchoconでAWS APIへの接続を高速化する
2017/06/08 「AWS CLIの実行」に注意書きを追加
ども、大瀧です。
先週開催されたAWS Summit Tokyoでは、メルカリSREの@kazeburoさんのセッションにてプロキシサーバーchoconを活用したリージョン間アクセスの高速化事例が紹介されました。
プロキシ元であるクライアントとプロキシ先のAPIエンドポイントとのHTTPSセッションを集約することで、Keepaliveによる高コストなHTTPSネゴシエーションの最小化やHTTP/2による効率の良いデータ転送を狙うもののようです *1。AWSのRESTful APIはちょうどHTTPSですので、choconをAWS APIの呼び出しに使えないかなぁと思い、試してみた様子をご紹介します *2。
動作検証環境
- OS : macOS Sierra
- golang : バージョン1.7
セットアップ
GitHubのREADMEに従い、choconをインストールします。Makefileがglideに依存するので、先にHomebrewでインストールしました。make glide
でもイケるかもしれません。
$ brew install glide ==> Installing glide ==> Downloading https://homebrew.bintray.com/bottles/glide-0.12.3.sierra.bottle.tar.gz ######################################################################## 100.0% ==> Pouring glide-0.12.3.sierra.bottle.tar.gz ? /usr/local/Cellar/glide/0.12.3: 6 files, 10MB $ go get -u github.com/kazeburo/chocon $ cd .go/src/github.com/kazeburo/chocon/ $ make bundle glide install [INFO] Downloading dependencies. Please wait... [INFO] --> Fetching github.com/lestrrat/go-apache-logformat. [INFO] --> Fetching github.com/satori/go.uuid. [INFO] --> Fetching github.com/lestrrat/go-server-starter-listener. [INFO] --> Fetching github.com/renstrom/shortuuid. : $ make go build -ldflags "-X main.Version=0.7.0" chocon.go $ chocon -h Usage: chocon [OPTIONS] Application Options: -l, --listen= address to bind (default: 0.0.0.0) -p, --port= Port number to bind (default: 3000) --access-log-dir= directory to store logfiles --access-log-rotate= Number of day before remove logs (default: 30) -v, --version Show version -c, --keepalive-conns= maximun keepalive connections for upstream (default: 2) --read-timeout= timeout of reading request (default: 30) --write-timeout= timeout of writing response (default: 90) --proxy-read-timeout= timeout of reading response from upstream (default: 60) Help Options: -h, --help Show this help message $
これでOKです。
choconの実行
chocon
コマンドで実行します。今回はこのあとのAWS CLIのコマンドラインをシンプルにしたかったので、sudo
を使って80番ポートをListenしました。デフォルトの3000番などであればsudo
による実行は不要です。
$ sudo chocon -p 80 Password: Macのユーザーのパスワードを入力 (なにも表示されない)
他のターミナルからcURL
でアクセスしてみると
$ curl localhost $
以下のように、choconを実行する端末にアクセスログ(今回はプロキシアクセスのための情報が足りないため400エラー)が表示され、動いている様子がわかります。
$ sudo chocon -p 80 Password: [::1]:49265 - - [06/Jun/2017:00:04:31 +0900] "GET / HTTP/1.1" 400 - "localhost" 0.52.441796 6oFvpnTv5EgEm8zHJvQCC5
AWS CLIの実行
では、今回はAWS APIにアクセスするためにAWS CLIを利用してみます。choconはリクエストのHostヘッダを以下の規則で見て、プロキシ先を動的に決定します。
<プロキシ先ドメイン名>.ccnproxy-{http|https}
今回はAmazon S3バージニアリージョン(s3.amazonaws.com
)へのアクセスを試してみたいので、/etc/hosts
ファイルに以下のように追加します。
127.0.0.1 s3.amazonaws.com.ccnproxy-https
これで、s3.amazonaws.com.ccnproxy-https
のアクセスが127.0.0.1
(ローカルホストのchocon)を向き、それがchoconに届くとs3.amazonaws.com
のHTTPSへプロキシされるわけです。
それでは試してみましょう(AWS CLIにはあらかじめAPIキーなどを設定済みです)。
$ aws s3 ls --endpoint http://s3.amazonaws.com.ccnproxy-https 2016-12-01 17:30:39 aws-athena-query-results-XXXXXXXXXXXX-us-west-2 : $
お、AWSからのレスポンスは正常に返ってきているようです。choconを実行するターミナルを見てみると...
127.0.0.1:49296 - - [06/Jun/2017:00:12:02 +0900] "GET / HTTP/1.1" 200 8472 "s3.amazonaws.com.ccnproxy-https" 1.723.21232 KZmTLy6tE5g2UMydCx9eg8
それらしいログが残っていますね!ソースを見ると9カラム目(1.723.21232
)がオリジンとのリクエスト/レスポンス送受信にかかった時間に見えます。
なので、同じaws
コマンドを何度か試してアクセスが早くなるか様子を見てみましょう。
127.0.0.1:49371 - - [06/Jun/2017:00:18:10 +0900] "GET / HTTP/1.1" 200 8472 "s3.amazonaws.com.ccnproxy-https" 1.331.463509 JLmGMKUiMgahtzsUyR5sUY 127.0.0.1:49374 - - [06/Jun/2017:00:18:13 +0900] "GET / HTTP/1.1" 200 8472 "s3.amazonaws.com.ccnproxy-https" 0.419.019149 K3qUtdo5zPXWKT6imCVh6Y 127.0.0.1:49376 - - [06/Jun/2017:00:18:15 +0900] "GET / HTTP/1.1" 200 8472 "s3.amazonaws.com.ccnproxy-https" 0.626.820031 o7SCdEYV8PQgG5gRf96Bq3 127.0.0.1:49378 - - [06/Jun/2017:00:18:17 +0900] "GET / HTTP/1.1" 200 8472 "s3.amazonaws.com.ccnproxy-https" 0.573.527977 5e9f4vGBPQWYf8eYd38zWZ 127.0.0.1:49380 - - [06/Jun/2017:00:18:19 +0900] "GET / HTTP/1.1" 200 8472 "s3.amazonaws.com.ccnproxy-https" 0.424.053241 Dvsz3yjXg7T8dD3Mo8wtAn 127.0.0.1:49382 - - [06/Jun/2017:00:18:21 +0900] "GET / HTTP/1.1" 200 8472 "s3.amazonaws.com.ccnproxy-https" 0.325.698352 8DdyYhewJQ9oTLrtVCyRQH 127.0.0.1:49384 - - [06/Jun/2017:00:18:23 +0900] "GET / HTTP/1.1" 200 8472 "s3.amazonaws.com.ccnproxy-https" 0.124.282789 rYU4Am5kAS7SBzgT9SQs9L 127.0.0.1:49386 - - [06/Jun/2017:00:18:25 +0900] "GET / HTTP/1.1" 200 8472 "s3.amazonaws.com.ccnproxy-https" 0.10.013781 J8jtkQQLoiETLVHnSqr9Md 127.0.0.1:49390 - - [06/Jun/2017:00:18:27 +0900] "GET / HTTP/1.1" 200 8472 "s3.amazonaws.com.ccnproxy-https" 0.35.882492 LC9eN6sPz25EaLotTEGvhB 127.0.0.1:49392 - - [06/Jun/2017:00:18:28 +0900] "GET / HTTP/1.1" 200 8472 "s3.amazonaws.com.ccnproxy-https" 0.976.821096 J3KVb6AQpUsRRkcGrbgrsb
2回目以降の時間が短くなっていることが分かりますね!KeepaliveでS3 APIとのコネクションを維持することで個々のリクエスト/レスポンス処理が高速化できているんじゃないでしょうか。
AWSのAPIはサービスごとにリクエストの規則が異なるため、サービスによってはエラーになることがあります。今回S3は通りましたが、DynamoDBではAWS V4署名に関するエラーでAWS CLIを実行することができませんでした。
AWS環境にデプロイするなら
今回はローカルのMacで試してみましたが、AWS環境で構成するのであればいろいろ工夫のしがいがありそうです。クライアント-chocon間のリクエストは通常のHTTPですので、ELBを間に噛ませてchoconプロキシインスタンスを冗長構成にするのがいいかなと思います。また、他のAWSサービスやリージョンに対応させるとなるとhostsファイルではしんどくなってくると思うので、発表スライドにあるような内部DNSを利用するのが良いかなと思います。ただし、Route 53はピリオドを含むサブドメインのワイルドカードが表現できないので、dnsmasqなどサブドメイン表現が柔軟にできるものをEC2のローカルに用意しちゃうのがおすすめです。
まとめ
choconを利用して、AWS APIへのアクセスを高速化する様子をご紹介しました。DynamoDBやKinesis、S3など頻繁にデータをやり取りするサービスで大きな効力を発揮するのではないでしょうか。一方でそれらのサービスはDNSのTTLが短くDNSによってAWS側ノードの負荷分散を意識しているので、choconサーバーのインスタンス数をある程度用意しないと、choconプロキシ-AWS間で負荷が偏りボトルネックになる恐れもあります。
あとどうでもいいことですが、ソフトウェア名は某幼児向け番組の物知りキャラから来ているんですかね。気になるー。
参考URL
- 【資料公開します】AWS Dev Day Tokyo 2017 にて登壇しました/choconの簡単なご紹介 - Mercari Engineering Blog
- Cloud connect the world as a Glue - AWS Dev Day 2017 // Speaker Deck
- kazeburo/choconと、それを支えるnet/httpの実装について – timakin – Medium
- r7kamura/entoverse: A library to implement host-based HTTP reverse-proxy in Golang.